﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <thread> //线程库
#include <list>
#include <mutex> //互斥锁
#include <atomic> //原子操作库
#include <condition_variable> //条件变量
#include <functional>
#include <map>
#include <string>
using namespace std;

//int x = 0;
//mutex m;
//list<int> lt;
//
////并行
//void func1(int n)
//{
//	for (int i = 0; i < n; ++i)
//	{
//		m.lock();
//		++x;
//		//lt.push_back(i);
//		cout << this_thread::get_id() << "|" << x << endl;
//		m.unlock();
//	}
//}
//
////串行 - 在频繁操作少的情况下，串行快，但是如果执行的命令多则相差不多
//void func2(int n)
//{
//	m.lock();
//	for (int i = 0; i < n; ++i)
//	{
//		++x;
//		//lt.push_back(i);
//		cout << this_thread::get_id() << "|" << x << endl;
//	}
//	m.unlock();
//}
//
//int main()
//{
//	int n = 10000;
//	size_t times = clock();
//	thread t1(func1, n), t2(func1, n);
//
//	t1.join();
//	t2.join();
//	cout << clock() - times << endl;
//	cout << x << endl;
//
//
//	return 0;
//}

//int main()
//{
//	int x = 0;
//	mutex m;
//	int n = 1000000;
//	//thread t1([&, n] {
//	//	for (int i = 1; i <= n; ++i)
//	//	{
//	//		m.lock();
//	//		++x;
//	//		m.unlock();
//	//	}
//	//	});
//
//	//thread t2([&, n] {
//	//	for (int i = 1; i <= n; ++i)
//	//	{
//	//		m.lock();
//	//		++x;
//	//		m.unlock();
//	//	}
//	//	});
//
//	thread t1([&, n] {
//		m.lock();
//		for (int i = 1; i <= n; ++i)
//		{
//			++x;
//		}
//		m.unlock();
//		});
//
//	thread t2([&, n] {
//		m.lock();
//		for (int i = 1; i <= n; ++i)
//		{
//			++x;
//		}
//		m.unlock();
//		});
//	
//	t1.join();
//	t2.join();
//	cout << x << endl;
//
//	return 0;
//}



//当我们使用递归时，普通互斥锁可能会卡在下一个同函数的栈帧申请锁处 也就是一个函数递归申请了两次锁把自己死锁了
//此时需要使用递归锁,其次我们可以使用lock_graud和unique_lock
//recursive_mutex m;
//int x = 0;
//
//void func(int n)
//{
//	//m.lock();
//	//unique_lock<recursive_mutex> ul(m);
//	if (n == 0)
//	{
//		//m.unlock();
//		return;
//	}
//	++x;
//	func(n - 1);
//	//m.unlock();
//}
//
//int main()
//{
//
//	int n = 100;
//	thread t1(func, n);
//	thread t2(func, n);
//
//
//	t1.join();
//	t2.join();
//	cout << x << endl;
//
//	return 0;
//}


//对于一些作用域内使用的锁 可以使用RAII的lock_guard和unique_lock
//int main()
//{
//	mutex m;
//	int x = 0;
//	int n = 1000000;
//	auto func = [&, n] {
//		for (int i = 0; i < n; ++i)
//		{
//			//lock_guard<mutex> lg(m);
//			//unique_lock<mutex> ul(m);
//			++x;
//		}
//	};
//
//	thread t1(func);
//	thread t2(func);
//	t1.join();
//	t2.join();
//
//	cout << x << endl;
//
//	return 0;
//}


//出了以上加锁的办法进行互斥以外，还可以使用原子操作
//atomic<int> x = 0;
////int x = 0;
//
//void func(int n)
//{
//	for (int i = 0; i < n; ++i)
//	{
//		++x;
//	}
//}
//
//
//int main()
//{
//	int n = 10000;
//	thread t1(func,n);
//	thread t2(func,n);
//	t1.join();
//	t2.join();
//	cout << x << endl;
//	return 0;
//}


//两个线程交替打印，一个打印奇数一个打印偶数
//int main()
//{
//	int x = 1;
//	int n = 1000;
//	mutex m;
//	condition_variable cv;
//
//	thread t1([&, n] {
//		while (true)
//		{
//			unique_lock<mutex> ul(m);
//			if (x >= n) break;
//			//if (x % 2 != 0) cv.wait(ul); //防止该线程还处于时间片中 连续抢锁打印的问题
//			//奇数就阻塞
//			cv.wait(ul, [&] {return x % 2 == 0; });
//			//这里如果不使用条件控制阻塞，当一个线程时间片足够长，会两次进行运行，此时会wait，两个线程都进入等待队列等待无法被唤醒，要保证一个线程条件满足时一定能打印
//			cout << this_thread::get_id() << "| 偶数：" << x << endl;
//			++x;
//			cv.notify_one();
//		}
//
//		});
//
//	thread t2([&, n] {
//		while (true)
//		{
//			unique_lock<mutex> ul(m);
//			if (x >= n) break;
//			//if (x % 2 == 0) cv.wait(ul);
//			//偶数就阻塞
//			cv.wait(ul, [&] {return x % 2 != 0; }); //也可以使用条件阻塞的方式 - 不满足函数条件则阻塞
//
//			cout << this_thread::get_id() << "| 奇数：" << x << endl;
//			++x;
//			cv.notify_one(); //唤醒线程
//		}
//
//		});
//	
//	t1.join();
//	t2.join();
//
//
//	return 0;
//}


//function包装器使用
//template<class T>
//struct funca
//{
//	T operator()(T a, T b) { return a + b; }
//};
//
//template<class T>
//T funcb(T a, T b) { return a + b; }
//
//int main()
//{
//	//function<函数返回值(函数参数类型)>
//	function<int(int, int)> f1 = funca<int>();
//	function<int(int, int)> f2 = funcb<int>;
//	function<int(int, int)> f3 = [](int a, int b) {return a + b; };
//	map<string, function<int(int, int)>> m;
//	m["func"] = f2;
//	m["funcobj"] = f1;
//	m["lambda"] = f3;
//
//	cout << m["func"](1, 2) << endl;
//	cout << m["funcobj"](1, 2) << endl;
//	cout << m["lambda"](1, 2) << endl;
//
//
//	//cout << f1(1, 2) << endl;
//	//cout << f2(1, 2) << endl;
//	//cout << f3(1, 2) << endl;
//
//	return 0;
//}


//关于function包装器包装对象函数
//class Plus
//{
//public:
//	 static int plusi(int a, int b)
//	 {
//		return a + b;
//	 }
//	 double plusd(double a, double b)
//	 {
//		return a + b;
//	 }
//};
//
//int main()
//{
//	function<int(int, int)> f1 = Plus::plusi; //对于静态函数，使用方法与普通函数一样
//	function<int(Plus,int, int)> f2 = &Plus::plusd; //对于普通成员函数，需要传递this指针类型 - this指针的类型
//	function<int(Plus*, int, int)> f3 = &Plus::plusd; //对于普通成员函数，需要传递this指针类型 - 传递this类型的指针
//
//	cout << f1(1, 2) << endl;
//	cout << f2(Plus(),1, 2) << endl; //对于传递类类型的 只需要传递匿名构造使用移动构造即可
//	Plus p;
//	cout << f3(&p,1, 2) << endl; //对于传递类类型栈帧，只能使用左值，必须先实例对象才能使用(匿名构造理论上是右值无法取地址) 这里相当于是p.plusd(1,2)
//
//	return 0;
//}